We are migrating the bug tracker to github Issues. This is now the preferred way to report NASM bugs.

Self-registration is disabled due to spam issue (mail gorcunov@gmail.com or hpa@zytor.com to create an account)

Bug 3392654 - Certain testcase with -felf -g results in segmentation fault
Summary: Certain testcase with -felf -g results in segmentation fault
Status: CLOSED FIXED
Alias: None
Product: NASM
Classification: Unclassified
Component: Assembler (show other bugs)
Version: 2.15.xx
Hardware: All All
: Medium severe
Assignee: nobody
URL:
: 3392661 (view as bug list)
Depends on:
Blocks:
 
Reported: 2020-03-23 04:00 PDT by E. C. Masloch
Modified: 2020-05-06 15:59 PDT (History)
6 users (show)

Obtained from: Built from git using configure
Generated by: ---
Bug category:
Observed for: ---
Regression: ---
Regression since:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description E. C. Masloch 2020-03-23 04:00:11 PDT
This is running with nasm-2.14.03rc2-448-gca2d991e from https://github.com/ecm-pushbx/nasm/commit/ca2d991ec9240cb35bad9cd467aea1eab197784d

The following example results in a segmentation fault when assembling to ELF format with debugging information (-felf -g). Assembling without debugging information or to bin format instead does not exhibit this problem. If I drop the second lpar usage, or the lleave, the error also does not occur any longer.

$ nasm --version
NASM version 2.15rc0 compiled on Nov 22 2019
$ cat test.asm
%include "lmacros2.mac"

	bits 32

	lframe near
	lpar dword,	EKey
	lpar dword,	length
	lenter
	lleave

$ hg -R ../lmacros/ id
aa2ecb95d799 tip
$ nasm -felf -g test.asm -o test.o -I ../lmacros/
Segmentation fault
$ nasm -felf test.asm -o test.o -I ../lmacros/
$ nasm -fbin -g test.asm -o test.o -I ../lmacros/
$ nasm -fbin test.asm -o test.o -I ../lmacros/
$ 

This example uses lmacros2.mac and lmacros1.mac from https://hg.ulukai.org/ecm/lmacros/rev/aa2ecb95d799 and the expected output is:

$ nasm -fbin -g test.asm -o test.o -I ../lmacros/ -l /dev/stderr
     1                                  %include "lmacros2.mac"
     1                              <1> [list -]
    14                              <1> [list -]
     2                                  
     3                                  	bits 32
     4                                  
     5                                  	lframe near
     6                                  	lpar dword,	EKey
     7                                  	lpar dword,	length
     8 00000000 5589E5                  	lenter
     9 00000003 5D                      	lleave
    10                                  
$ 

That is, "push ebp" \ "mov ebp, esp" \ "pop ebp" in the default section.
Comment 1 E. C. Masloch 2020-03-23 04:03:03 PDT
Here's the relevant part of the listing output with the -Ls switch, when assembling into bin format.

$ nasm -fbin -g test.asm -o test.o -I ../lmacros/ -l /dev/stderr -Ls
[...]
     1                                  %include "lmacros2.mac"
     1                              <1> [list -]
[...]
     2                                  
     3                                  	bits 32
     4                                  
     5                                  	lframe near
     5                                   ;;; %define [LFRAME::11] %$bits 32
     5                                   ;;; %define [LFRAME::11] %$base_size 4
     5                                   ;;; %define [LFRAME::11] %$near_offset 4
     5                                   ;;; %define [LFRAME::11] %$far_offset 8
     5                                   ;;; %define [LFRAME::11] %$int_offset 12
     5                                   ;;; %define [LFRAME::11] %$inner 0
     5                                   ;;; %define [LFRAME::11] %$nested 0
     5                                   ;;; %define [LFRAME::11] %$autoret 
     5                                   ;;; %define [LFRAME::11] %$autoret near
     5                                   ;;; %define [LFRAME::11] %$parofs 4
     5                                   ;;; %define [LFRAME::11] %$pars_size 0
     5                                   ;;; %define [LFRAME::11] %$pars_return_size 0
     5                                   ;;; %define [LFRAME::11] %$parlist 
     5                                   ;;; %define [LFRAME::11] %$labellist empty,empty,empty
     5                                   ;;; %define [LFRAME::11] %$ofs 0
     5                                   ;;; %define [LFRAME::11] %$enter 0
     5                                   ;;; %define [LFRAME::11] %$req 0
     5                                   ;;; %define [LFRAME::11] %$usereq 0
     5                                   ;;; %define [LFRAME::11] %$emit 1
     5                                   ;;; %define [LFRAME::11] %$restore_frame_ofs 0
     5                                   ;;; %define [LFRAME::11] %$pars_inner_size 0
     6                                  	lpar dword,	EKey
     6                                   ;;; %define [LFRAME::11] %$varsize 4
     6                                   ;;; %define [LFRAME::11] %$newlabel EKey
     6                                   ;;; %define [LFRAME::11] %$labellist EKey,undefined,,empty,empty,empty
     6                                   ;;; %define [LFRAME::11] %$pars_size 4
     6                                   ;;; %define [LFRAME::11] %$parlist 4,EKey
     6                                   ;;; %define [LFRAME::11] %$req 1
     7                                  	lpar dword,	length
     7                                   ;;; %define [LFRAME::11] %$varsize 4
     7                                   ;;; %define [LFRAME::11] %$newlabel length
     7                                   ;;; %define [LFRAME::11] %$labellist length,undefined,,EKey,undefined,,empty,empty,empty
     7                                   ;;; %define [LFRAME::11] %$pars_size 8
     7                                   ;;; %define [LFRAME::11] %$parlist 4,EKey,4,length
     7                                   ;;; %define [LFRAME::11] %$req 1
     8 00000000 5589E5                  	lenter
     8                                   ;;; %define [LFRAME::11] %$wasearly 0
     8                                   ;;; %define [LFRAME::11] %$early 0
     8                                   ;;; %define [LENTER::11] %$lsizevariables 0
     8                                   ;;; %define [LENTER::11] %$req 1
     8                                   ;;; %define [LENTER::11] %$enter_emitted 0
     8                                   ;;; %define [LENTER::11] %$enter 1
     8                                   ;;; %define [LENTER::11] %$186 0
     8                                   ;;; %define [LENTER::11] %$newlabel frame_ebp
     8                                   ;;; %define [LENTER::11] %$labellist frame_ebp,undefined,,length,undefined,,EKey,undefined,,empty,empty,empty
     8                                   ;;; %define ?frame_ebp 0
     8                                   ;;; %define [LENTER::11] %$newlabel frame_eip
     8                                   ;;; %define [LENTER::11] %$labellist frame_eip,undefined,,frame_ebp,undefined,,length,undefined,,EKey,undefined,,empty,empty,empty
     8                                   ;;; %define ?frame_eip 4
     8                                   ;;; %define [LENTER::11] %$lsizeparameters 8
     8                                   ;;; %define [LENTER::11] %$pars_size 4
     8                                   ;;; %define ?EKey 12
     8                                   ;;; %define [LENTER::11] %$pars_size 0
     8                                   ;;; %define ?length 8
     9 00000003 5D                      	lleave
     9                                   ;;; %define [LENTER::11] %$186 0
     9                                   ;;; %define [LENTER::11] %$186 0
     9                                   ;;; %define lsizeparameters 8
     9                                   ;;; %define __lframe__autoret near
    10                                  
$
Comment 2 E. C. Masloch 2020-03-23 04:43:22 PDT
Not sure whether this is just one and the same error, but I do get a segmentation fault even with only a single instruction and -felf -g. However, this only happens if there is a trailing empty line.

$ (echo; echo "pop ebp"; echo) > test1.asm
$ nasm -felf -g test1.asm -o test1.o
Segmentation fault
$ (echo; echo "pop ebp") > test2.asm
$ nasm -felf -g test2.asm -o test2.o
$
Comment 3 Chang S. Bae 2020-04-07 16:34:49 PDT
The test
    $ nasm -felf -g test.asm -o test.o -I ../lmacros/
looks to be working with the latest commit (e91f5cc1322e) without segfault.
Comment 4 E. C. Masloch 2020-04-08 00:22:44 PDT
I forked my local NASM repo and checked out nasm-2.14.03rc2-445-ge91f5cc1 then tested that. Result is the same as with ca2d991ec, crashes with -felf -g:

$ cat test.asm
%include "lmacros2.mac"

	bits 32

	lframe near
	lpar dword,	EKey
	lpar dword,	length
	lenter
	lleave

$ tstnasm --version
NASM version 2.15rc0 compiled on Apr  8 2020
$ hg -R ../lmacros/ id
aa2ecb95d799 tip
$ tstnasm -felf -g test.asm -o test.o -I ../lmacros/
Segmentation fault
$ tstnasm -felf test.asm -o test.o -I ../lmacros/
$ tstnasm -fbin -g test.asm -o test.o -I ../lmacros/
$ tstnasm -fbin test.asm -o test.o -I ../lmacros/
$
Comment 5 E. C. Masloch 2020-04-08 00:45:54 PDT
This line is causing the segfault:

https://repo.or.cz/nasm.git/blob/e91f5cc1322eed4da0de81656276e021bf352c3d:/output/outelf.c#l2964

(Recompiled after ./configure --enable-gdb. Tests segfault the same as without that switch.)

$ gdb --args tstnasm -felf -g test1.asm -o test1.o
GNU gdb (Debian 9.1-2) 9.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from tstnasm...
(gdb) run
Starting program: /home/[...]/tstnasm -felf -g test1.asm -o test1.o

Program received signal SIGSEGV, Segmentation fault.
dwarf_output (type=64, param=0x5555556ff6c0 <sinfo>) at output/outelf.c:2965
2965	    if (!(sects[s->section]->flags & SHF_EXECINSTR))
(gdb) print s
$1 = (struct symlininfo *) 0x5555556ff6c0 <sinfo>
(gdb) print sects
$2 = (struct elf_section **) 0x555555757bc0
(gdb) print s->section
$3 = 1
(gdb) print sects[s->section]
$4 = (struct elf_section *) 0x0
(gdb) print *sects
$5 = (struct elf_section *) 0x555555747aa0
(gdb) print **sects
$6 = {data = 0x555555747b20, len = 0, size = 0, nrelocs = 0, index = 16, 
  shndx = 1, type = 1, align = 16, flags = 6, pass_last_seen = 0, entsize = 0, 
  name = 0x555555757ba0 ".text", rel = 0x0, head = 0x0, tail = 0x555555747b00, 
  gsyms = 0x0}
(gdb) print *sects[s->section]
Cannot access memory at address 0x0
(gdb) print sects[s->section]
$7 = (struct elf_section *) 0x0
(gdb) quit
A debugging session is active.

	Inferior 1 [process 1705047] will be killed.

Quit anyway? (y or n) y


This patch fixes the issue for me:

$ git diff
diff --git a/output/outelf.c b/output/outelf.c
index 4976b680..7dc1a52c 100644
--- a/output/outelf.c
+++ b/output/outelf.c
@@ -2961,6 +2961,9 @@ static void dwarf_output(int type, void *param)
 
     s = (struct symlininfo *)param;
 
+    if (!sects[s->section])
+        return;
+
     /* line number info is only gathered for executable sections */
     if (!(sects[s->section]->flags & SHF_EXECINSTR))
         return;
Comment 6 Chang S. Bae 2020-04-21 13:47:38 PDT
The example in BR3392661 touches the same issue here. So, while the attached example is reproducible on my side, strangely enough, I think the fix justifiable.
Comment 7 Chang S. Bae 2020-04-21 15:58:53 PDT
Looking further into this, I think it should fix the index number, using 's->section - 1' instead of 's->section'. Yes, as someone pointed out in the other bug report, the debug out was not correctly populated with this issue.
Comment 8 mae.bdf 2020-04-21 17:20:37 PDT
*** Bug 3392661 has been marked as a duplicate of this bug. ***
Comment 9 E. C. Masloch 2020-04-22 14:00:25 PDT
Here is an additional trivial testcase with a few more test results.

* "nasm" is nasm-2.14.03rc2-448-gca2d991e from https://github.com/ecm-pushbx/nasm/commit/ca2d991ec9240cb35bad9cd467aea1eab197784d

* "oldnasm" is 2.12.02

* "tstnasm" is based on nasm-2.14.03rc2-445-ge91f5cc1 from https://repo.or.cz/nasm.git/commit/e91f5cc1322eed4da0de81656276e021bf352c3d with the additional patch I proposed in comment #5 which is this:

$ git diff
diff --git a/output/outelf.c b/output/outelf.c
index 4976b680..7dc1a52c 100644
--- a/output/outelf.c
+++ b/output/outelf.c
@@ -2961,6 +2961,9 @@ static void dwarf_output(int type, void *param)
 
     s = (struct symlininfo *)param;
 
+    if (!sects[s->section])
+        return;
+
     /* line number info is only gathered for executable sections */
     if (!(sects[s->section]->flags & SHF_EXECINSTR))
         return;
$

* "patnasm" is based on the same revision as tstnasm but has instead the following patch, based on the comment #7:

$ git diff
diff --git a/output/outelf.c b/output/outelf.c
index 4976b680..6175ca48 100644
--- a/output/outelf.c
+++ b/output/outelf.c
@@ -2962,12 +2962,12 @@ static void dwarf_output(int type, void *param)
     s = (struct symlininfo *)param;
 
     /* line number info is only gathered for executable sections */
-    if (!(sects[s->section]->flags & SHF_EXECINSTR))
+    if (!(sects[s->section - 1]->flags & SHF_EXECINSTR))
         return;
 
     /* Check if section index has changed */
-    if (!(dwarf_csect && (dwarf_csect->section) == (s->section)))
-        dwarf_findsect(s->section);
+    if (!(dwarf_csect && (dwarf_csect->section) == (s->section - 1)))
+        dwarf_findsect(s->section - 1);
 
     /* do nothing unless line or file has changed */
     if (!debug_immcall)
$


Here is the test case and the results of assembling it with -felf -g, then dumping the disassembly + source with objdump -S:

$ cat test.asm

section .text
global foo
foo:
	mov eax, 1234
	retn
$ nasm -v
NASM version 2.15rc0 compiled on Nov 22 2019
$ nasm -felf -g test.asm -o test.o
Segmentation fault
$ nasm -felf test.asm -o test.o
$ objdump -S test.o

test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <foo>:
   0:	b8 d2 04 00 00       	mov    $0x4d2,%eax
   5:	c3                   	ret    
$ oldnasm -v
NASM version 2.12.02 compiled on Aug 10 2019
$ oldnasm -felf -g test.asm -o test.old
$ objdump -S test.old

test.old:     file format elf32-i386


Disassembly of section .text:

00000000 <foo>:

section .text
global foo
foo:
	mov eax, 1234
   0:	b8 d2 04 00 00       	mov    $0x4d2,%eax
	retn
   5:	c3                   	ret    
$ tstnasm -v
NASM version 2.15rc0 compiled on Apr  8 2020
$ tstnasm -felf -g test.asm -o test.tst
$ objdump -S test.tst

test.tst:     file format elf32-i386


Disassembly of section .text:

00000000 <foo>:
   0:	b8 d2 04 00 00       	mov    $0x4d2,%eax
   5:	c3                   	ret    
$ patnasm -v
NASM version 2.15rc0 compiled on Apr 22 2020
$ patnasm -felf -g test.asm -o test.pat
$ objdump -S test.pat

test.pat:     file format elf32-i386


Disassembly of section .text:

00000000 <foo>:

section .text
global foo
foo:
	mov eax, 1234
   0:	b8 d2 04 00 00       	mov    $0x4d2,%eax
	retn
   5:	c3                   	ret    
$ 


My earlier patch (tstnasm) does not have any source line debugging information for the .text section of this example case. The newer patch (patnasm) seems to restore that info to be as it should. Note that I only patched the most obvious references in the dwarf_output function; I expect that the change should be done in other places too. Or whatever changed the section numbering to be 1-based should be reverted.
Comment 10 Chang S. Bae 2020-04-22 14:05:21 PDT
I ended up with this patch in the way which used to be in some old codes:

https://repo.or.cz/nasm.git/commitdiff/74b2731f2cef0f1ec8c0c6e6e3dee9492b851e8c
Comment 11 E. C. Masloch 2020-04-22 14:11:17 PDT
I just tested https://repo.or.cz/nasm.git/commitdiff/74b2731f2cef0f1ec8c0c6e6e3dee9492b851e8c and it seems to succeed, no crash and with debugging information present:

$ patnasm -v
NASM version 2.15rc0 compiled on Apr 22 2020
$ patnasm -felf -g test.asm -o test.pat
$ objdump -S test.pat

test.pat:     file format elf32-i386


Disassembly of section .text:

00000000 <foo>:

section .text
global foo
foo:
	mov eax, 1234
   0:	b8 d2 04 00 00       	mov    $0x4d2,%eax
	retn
   5:	c3                   	ret    
$
Comment 12 Chang S. Bae 2020-04-22 14:13:12 PDT
Thank you!
Comment 13 Chang S. Bae 2020-05-06 15:59:02 PDT
The below commit should have resolved the issue:


commit	74b2731f2cef0f1ec8c0c6e6e3dee9492b851e8c
author	Chang S. Bae <chang.seok.bae@intel.com>	
Tue, 21 Apr 2020 09:23:39 +0000 (21 09:23 +0000)
committer	Chang S. Bae <chang.seok.bae@intel.com>	
Wed, 22 Apr 2020 00:05:56 +0000 (22 00:05 +0000)
outelf: Fix the section index for the debug output

The section information delivered to the debug output has an index of the
section table. The index should be different from the total number of
sections at the moment, the returned value from add_sectname(). So, fix the
value.

Fixes: b2004511ddde ("ELF: handle more than 32,633 sections")